/*
 * @Author: 吴世扬 18368095041@163.com
 * @Date: 2022-09-08 15:34:35
 * @LastEditors: 吴世扬 18368095041@163.com
 * @LastEditTime: 2022-11-21 10:46:12
 * @FilePath: /vuecli508-datav/src/components/ui/ol-map/utils/index.js
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import { Style, Stroke, Icon, Fill, Text, Circle } from 'ol/style';
import { asArray } from 'ol/color';
import { Point } from 'ol/geom';
import { iconJin, iconQi, iconZhong } from './pic';
import { wgs84togcj02, gcj02towgs84 } from './transform';

export const tk = '5f4f8091b7a53f53ba069cdfa7bd4beb';
// 高德地图路线规划
export const amapTk = '9860e090dadc3c98c78409ec38cbd217'; // 吴世扬个人key
export { wgs84togcj02, gcj02towgs84 };

// params { start: { lng; lat; }; end: { lng; lat; }, url: string }
export const requestPlanning = (params) => {
    try {
        const param = JSON.parse(JSON.stringify(params));

        const [originLng, originLat] = wgs84togcj02(
            param.start.lng,
            param.start.lat
        );
        const [destinationLng, destinationLat] = wgs84togcj02(
            param.end.lng,
            param.end.lat
        );
        const postObj = {
            origin: `${originLng.toFixed(6)},${originLat.toFixed(6)}`,
            destination: `${destinationLng.toFixed(6)},${destinationLat.toFixed(
                6
            )}`,
            isindoor: 0,
            show_fields: 'polyline'
        };

        let postStr = '';
        const postObjKeys = Object.keys(postObj);
        postObjKeys.forEach((key) => {
            postStr += `${key}=${postObj[key]}&`;
        });

        postStr += `key=${amapTk}`;
        // console.log('请求参数', `https://restapi.amap.com/v5/direction/walking?${postStr}`);
        return fetch(`${params.url}?${postStr}`, { method: 'get' })
            .then((res) => res.json())
            .then((res) => {
                // console.log('路线规划请求成功',res);
                const { steps } = res.route.paths[0];
                const points = [
                    { lng: +param.start.lng, lat: +param.start.lat }
                ];
                steps.forEach((step) => {
                    const stepLineArr = step.polyline.split(';');
                    stepLineArr.forEach((p) => {
                        const coord = p.split(',');
                        const pwgs84 = gcj02towgs84(coord[0], coord[1]);
                        points.push({ lng: +pwgs84[0], lat: +pwgs84[1] });
                    });
                });
                points.push({ lng: +param.end.lng, lat: +param.end.lat });
                return {
                    path: points,
                    points: param
                };
            })
            .catch((err) => {
                console.log('路线规划请求失败', err);
                return new Error('路线规划请求失败');
            });
    } catch (err) {
        console.log('路线规划函数错误', err);
        return Promise.reject(new Error('路线规划函数错误'));
    }
};

// params = { points: { lng; lat; }[], type } 传入wgs84坐标的点
// type 1 汽车 2 步行
export const getRoutePlanning = (params) => {
    const param = JSON.parse(JSON.stringify(params));
    const pros = [];
    const len = param.points.length;
    for (let i = 1; i < len; i++) {
        const lastPoint = param.points[i - 1];
        const point = param.points[i];
        // console.log('循环请求参数', { start: lastPoint, end: point })
        if (params.type === 1) {
            pros.push(
                requestPlanning({
                    start: lastPoint,
                    end: point,
                    url: 'https://restapi.amap.com/v5/direction/driving'
                })
            );
        } else if (params.type === 2) {
            pros.push(
                requestPlanning({
                    start: lastPoint,
                    end: point,
                    url: 'https://restapi.amap.com/v5/direction/walking'
                })
            );
        }
    }
    return Promise.all(pros).then((res) => {
        const points = [];
        res.forEach((item, index) => {
            let { path } = item;
            if (index !== res.length - 1) {
                path = path.slice(0, -1);
            }
            path.forEach((point) => {
                points.push(point);
            });
        });
        const result = {
            path: points,
            points: param.points.map((item, index) => {
                item.iconUrl = iconJin;
                if (index === 0) {
                    item.iconUrl = iconQi;
                } else if (index === param.points.length - 1) {
                    item.iconUrl = iconZhong;
                }
                item.label = '';
                item.scale = 0.7;
                item.offset = [0.5, 1];
                item.type = 'routePoint';
                return item;
            })
        };
        console.log('结果', result);
        return result;
    });
};

// 防抖
export const debounce = (func, wait = 0) => {
    let timeout;
    // eslint-disable-next-line
    return function (...rest) {
        const context = this;
        const args = rest;
        if (timeout) clearTimeout(timeout);
        if (wait === 0) {
            func.apply(context, args);
        } else {
            timeout = setTimeout(() => {
                func.apply(context, args);
            }, wait);
        }
    };
};

// 节流
export const throttle = (func, wait, type = 2) => {
    let previous = 0;
    let timeout = 0;
    // eslint-disable-next-line
    return function (...rest) {
        const context = this;
        const args = rest;
        if (type === 1) {
            const now = Date.now();
            if (now - previous > wait) {
                func.apply(context, args);
                previous = now;
            }
        } else if (type === 2) {
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null;
                    func.apply(context, args);
                }, wait);
            }
        }
    };
};

// 点位转角
export function setAngle(first, second) {
    var dx = second[0] - first[0];
    var dy = second[1] - first[1];
    var rotation = Math.atan2(dy, dx);
    return rotation;
}

// 线样式
// 线段a1、a2、a3、a4，则distances = [a1a4, a1a3, a1a2, a1a1];
// rotations = [a1a2方向、a2a3方向、a3a4方向];
export const createPolylineStyleFn = (option) => {
    return (feature, res) => {
        let geometry = feature.getGeometry();
        // const zoom = view.getZoom();
        const length = geometry.getLength();
        let styles = [
            new Style({
                stroke: new Stroke({
                    color: option.color || '#2dd18d',
                    lineCap: option.lineCap || 'round',
                    width: option.width || 2
                })
            })
        ];
        const rotations = [];
        const distances = [0];
        geometry.forEachSegment(function (start, end) {
            let dx = end[0] - start[0];
            let dy = end[1] - start[1];
            let rotation = Math.atan2(dy, dx);
            distances.unshift(Math.sqrt(dx ** 2 + dy ** 2) + distances[0]);
            rotations.push(rotation);
        });
        // border
        let borderStyles = [];
        if (option.border) {
            borderStyles.push(
                new Style({
                    stroke: new Stroke({
                        color: option.border.color || '#ffffff',
                        lineCap: option.lineCap || 'round',
                        width: (option.width || 2) + option.border.width
                    })
                })
            );
        }
        // label
        const labelStyle = [];
        if (option.label) {
            const labelCoord = geometry.getCoordinateAt(1 / 2);
            const labelCoordLinePos = distances[0] / 2;
            const point = new Point(labelCoord);
            const grid = distances.findIndex((x) => x <= labelCoordLinePos);
            const rotation = -rotations[distances.length - grid - 1];
            // console.log(mid);
            if (option.label.text) {
                labelStyle.push(
                    new Style({
                        geometry: point,
                        text: new Text({
                            text: option.label.text,
                            rotation,
                            scale: option.label.textScale || 1,
                            fill: new Fill({
                                color: '#ffffff'
                            })
                        })
                    })
                );
            }
            // console.log(option.label.iconUrl);
            if (option.label.iconUrl) {
                console.log(option.label.iconUrl);
                labelStyle.push(
                    new Style({
                        geometry: point,
                        image: new Icon({
                            rotation,
                            src: option.label.iconUrl,
                            scale: option.label.iconScale || 1
                        })
                    })
                );
            }
        }
        // pattern
        let patternStyles = [];
        if (option.pattern) {
            const gap = 10;
            const geoGap = gap * res;
            const arrowNum = Math.floor(length / geoGap);
            for (let i = 1; i < arrowNum; ++i) {
                const arrowCoord = geometry.getCoordinateAt(i / arrowNum);
                const d = i * geoGap;
                const grid = distances.findIndex((x) => x <= d);
                styles.push(
                    new Style({
                        geometry: new Point(arrowCoord),
                        image: new Icon({
                            src: option.pattern.iconUrl,
                            // opacity: 0.5,
                            // anchor: [0, 0],
                            rotateWithView: true,
                            // 读取 rotations 中计算存放的方向信息
                            rotation: -rotations[distances.length - grid - 1],
                            // size: [10, 15]
                            scale: 0.5 // 0.06
                        })
                    })
                );
            }
        }
        styles = [...borderStyles, ...styles, ...patternStyles, ...labelStyle];
        return styles;
    };
};

const paramterMap = new WeakMap();
// 点样式
export const createMarkerStyleFn = (option) => {
    // console.log(option);
    const hasBlink = !!option.blinkOption || option.isBlink;
    let jumpMaX = 1;
    let jumpMin = 0.5;
    let jumpSpeed = 0.02;
    let jump = 0.5;
    let radiusMax = 80;
    let radiusMin = 30;
    let radiusSpeed = 0.8;
    let radius = 60;
    let isAdd = true;
    if (hasBlink) {
        if (paramterMap.has(option)) {
            const data = paramterMap.get(option);
            jump = data.jump || 0.5;
            radius = data.radius || 60;
            isAdd = !!data.isAdd;
        }
        if (option.blinkOption) {
            if (typeof option.blinkOption.jumpSpeed === 'number') {
                jumpSpeed = option.blinkOption.jumpSpeed;
            }
            if (typeof option.blinkOption.radiusSpeed === 'number') {
                radiusSpeed = option.blinkOption.radiusSpeed;
            }
            if (Array.isArray(option.blinkOption.jumpRange)) {
                jumpMin = option.blinkOption.jumpRange[0];
                jumpMaX = option.blinkOption.jumpRange[1];
            }
            if (Array.isArray(option.blinkOption.radiusRange)) {
                radiusMin = option.blinkOption.radiusRange[0];
                radiusMax = option.blinkOption.radiusRange[1];
            }
        }
    }
    return (/* feature, res */) => {
        let styles = [];

        // 闪烁样式
        let bottomStyles = [];
        if (hasBlink) {
            const canvas = document.createElement('canvas');
            const context = canvas.getContext('2d');
            const grad = context.createRadialGradient(0, 0, 10, 0, 0, 100);
            let color;
            let isCustomColor = false;
            let scale = [1.6, 1];
            let displacement = [0, -10];
            if (option.blinkOption) {
                if (typeof option.blinkOption.color === 'string') {
                    color = option.blinkOption.color;
                    isCustomColor = true;
                } else if (Array.isArray(option.blinkOption.color)) {
                    option.blinkOption.color.forEach((item) => {
                        grad.addColorStop(item[0], item[1]);
                    });
                    isCustomColor = true;
                }
                option.blinkOption.scale && (scale = option.blinkOption.scale);
                option.blinkOption.displacement &&
                    (displacement = option.blinkOption.displacement);
            }
            if (!isCustomColor) {
                grad.addColorStop(0, 'rgba(255, 122, 0, 0)');
                grad.addColorStop(1, '#FF7A00');
                color = grad;
            }
            if (jump >= jumpMaX) {
                isAdd = false;
            } else if (jump <= jumpMin) {
                isAdd = true;
            }
            jump = isAdd ? jump + jumpSpeed : jump - jumpSpeed;
            if (radius >= radiusMax) radius = radiusMin;
            bottomStyles.push(
                new Style({
                    image: new Circle({
                        radius,
                        scale,
                        displacement,
                        fill: new Fill({
                            color,
                            opacity: 1
                        })
                    })
                })
            );
            radius += radiusSpeed; // 调整闪烁速度
            paramterMap.set(option, { jump, radius, isAdd });
        }
        // 图标样式
        let imgStyles = [];
        if (option.iconUrl) {
            if (hasBlink) {
                imgStyles.push(
                    new Style({
                        image: new Icon({
                            src: option.iconUrl,
                            scale: option.iconScale,
                            anchor: [0.5, jump]
                        })
                    })
                );
            } else {
                imgStyles.push(
                    new Style({
                        image: new Icon({
                            scale: option.iconScale,
                            src: option.iconUrl,
                            anchor: option.offset || [0.5, 0.5],
                            rotation: option.rotation || 0
                        })
                    })
                );
            }
        } else if (option.shape === 'circle') {
            imgStyles.push(
                new Style({
                    image: new Circle({
                        radius: option.radius,
                        fill: new Fill({
                            color: option.color, // 'rgba(255,0,0' + imageOpacity + ')',
                            opacity: 1
                        })
                        // displacement: [0, jump * option.radius]
                    })
                })
            );
        }
        // 标签样式
        let labelStyles = [];
        if (option.label) {
            labelStyles.push(
                new Style({
                    text: new Text({
                        text: option.label,
                        scale: option.labelScale || option.scale || 1,
                        offsetY: 25,
                        fill: new Fill({
                            color: '#ffffff'
                        }),
                        rotation: option.rotation || 0
                    })
                })
            );
        }
        styles = [...bottomStyles, ...imgStyles, ...labelStyles];
        return styles;
    };
};

// 多边形样式
export const createPolygonStyleFn = (option) => {
    return (/* feature, res */) => {
        let fillColor;
        if (typeof option.fillColor === 'string') {
            fillColor = asArray(option.fillColor);
            if (typeof option.fillOpacity === 'number') {
                fillColor[3] = option.fillOpacity;
            }
        }
        let strokeColor;
        if (typeof option.strokeColor === 'string') {
            strokeColor = asArray(option.strokeColor);
            if (typeof option.strokeOpacity === 'number') {
                strokeColor[3] = option.strokeOpacity;
            }
        }
        let styles = [
            new Style({
                stroke: new Stroke({
                    width:
                        typeof option.strokeWidth === 'number'
                            ? option.strokeWidth
                            : 1,
                    color: strokeColor || [0, 0, 255, 0.5]
                }),
                fill: new Fill({
                    color: fillColor || [204, 243, 255, 0.1]
                })
            })
        ];
        return styles;
    };
};
